﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using SCGILite.Helper;

namespace SCGILite.NetLib
{
    public class TcpSocketServer<T> where T : IAppSession
    {
        public virtual T ctorSession(ISocketSession tcp)
        {
            throw new Exception();
        }

        public IPEndPoint EndPoint { get; private set; }
        Socket listenSocket = null;
        SocketAsyncEventArgs acceptEventArg = new SocketAsyncEventArgs();

        public bool IsRunning
        {
            get { return Interlocked.CompareExchange(ref listenSocket, null, null) != null; }
        }

        int _backlog = 10;
        public int backlog
        {
            get
            {
                return _backlog;
            }
            set
            {
                if (_backlog == value)
                    return;
                _backlog = value;
                Free();
            }
        }

        #region _TcpSocketServer
        public TcpSocketServer(IPEndPoint localEndPoint)
        {
            EndPoint = localEndPoint;
            acceptEventArg.Completed +=
                (s, e) => { ProcessAccept(); };
        }
        #endregion

        #region Stop
        void Free()
        {
            SocketHelper.SafeCloseSocket(Interlocked.Exchange<Socket>(ref listenSocket, null));
        }
        public void Stop()
        {
            Free();
        }
        #endregion

        #region Start
        public void Start()
        {
            if (listenSocket != null)
                return;
            Socket sc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            Socket old = Interlocked.CompareExchange(ref listenSocket, sc, null);
            if (old != null)
            {
                SocketHelper.SafeCloseSocket(sc);
                return;
            }
            try
            {
                listenSocket.Bind(this.EndPoint);
                listenSocket.Listen(_backlog);
                StartAccept();
            }
            catch
            {
                Free();
            }
        }
        #endregion

        #region StartAccept
        void StartAccept()
        {
            Socket sc = Interlocked.CompareExchange<Socket>(ref listenSocket, null, null);
            if (sc == null)
                return;
            try
            {
                acceptEventArg.AcceptSocket = null;
                if (!sc.AcceptAsync(acceptEventArg))
                {
                    ProcessAccept();
                }
            }
            catch
            {
                Free();
            }                
        }
        #endregion

        #region ProcessAccept
        private void ProcessAccept()
        {
            if (listenSocket == null)
                return;
            try
            {
                Socket sc = acceptEventArg.AcceptSocket;
                acceptEventArg.AcceptSocket = null;
                if ((sc == null) || (sc.Connected == false) || (acceptEventArg.SocketError != SocketError.Success))// || (TcpSinglexAdapter.cnt > 3000) || (_OnAcceptRequest == null))
                {
                    Free();
                }
                else
                {
                    TcpSocketSession<T> ser = new TcpSocketSession<T>(sc);
                    T t = ctorSession(ser);
                    ser.Init(t);
                }
            }
            catch
            {
            }
            StartAccept();
        }
        #endregion
    }
}
